package com.tj.collection.utils;

import com.alibaba.fastjson.JSON;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.tj.collection.bean.RedisKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: pavan
 * Date: 2020/4/29
 * Time: 下午2:16
 */
@Component
public class DbCacheConfig {

    private static final Log LOGGER = LogFactory.getLog(DbCacheConfig.class);

    @PostConstruct
    public void initFieldValue() {
        try {
            InputStream is = DbCacheConfig.class.getResourceAsStream("/META-INF/app.properties");
            Properties properties = new Properties();
            properties.load(is);
            this.namespace = (String) properties.get("app.id");
        } catch (IOException e) {
            throw new RuntimeException("Configuration loading failed,[META-INF/app.properties]");
        }
    }

    private String namespace = "";

    @Autowired
    private RedisClient redisClient;

    public synchronized Map<String, Map<String, String>> reload(Map<String, Map<String, String>> paramsMap) {
        String currentTime = System.currentTimeMillis() + "";

        Map<String, Map<String, String>> oldParamsMap = new HashMap<>();

        String namespaceStr = redisClient.get(RedisKey.DB_CACHE_APP_LIST);
        if (namespaceStr != null && namespaceStr.length() > 0) {
            List<String> namespaceList = new ArrayList<>();
            Collections.addAll(namespaceList, namespaceStr.split(","));
            for (String namespace : namespaceList) {
                if (!paramsMap.containsKey(namespace)) {
                    redisClient.del(namespace);
                }
            }
        }

        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Map<String, String>> entry : paramsMap.entrySet()) {
            String redisKey = entry.getKey();
            Map<String, String> newParams = entry.getValue();
            newParams = newParams == null ? new HashMap<>() : newParams;

            Map<String, String> oldParams = redisClient.hGetAll(redisKey);
            oldParams = oldParams == null ? new HashMap<>() : oldParams;

            oldParamsMap.put(redisKey, oldParams);

            if (false) {
                //比较差异 剔除不在新参数列表中的key
                Set<String> oldKeySet = oldParams.keySet();
                Set<String> newKeySet = newParams.keySet();

                Set<String> differenceSet = new HashSet<>(oldKeySet);
                differenceSet.addAll(oldKeySet);
                differenceSet.removeAll(newKeySet);

                boolean setNewParamsFlag = true;

                if (differenceSet.size() > 0) {
                    for (String key : differenceSet) {
                        try {
                            redisClient.hDel(redisKey, key);
                        } catch (NoSuchMethodError e) {
                            //hDel 目前有些问题 暂时先这么处理
                            LOGGER.error("redishDel失败,redisKey:{}", redisKey, e);
                            redisClient.del(redisKey);
                            redisClient.hPutAll(redisKey, newParams);
                            setNewParamsFlag = false;
                            LOGGER.warn("redishDel失败,批量先删后插成功,redisKey:{},newParams:{}", redisKey, JSON.toJSONString(newParams));
                            break;
                        }
                    }
                }

                if (setNewParamsFlag) {
                    //写入新的配置
                    for (Map.Entry<String, String> subEntry : newParams.entrySet()) {
                        String paramKey = subEntry.getKey();
                        String value = subEntry.getValue();
                        redisClient.hPut(redisKey, paramKey, value);
                        LOGGER.info("新参数设置成功1,redisKey:{},key:{},value:{}", redisKey, paramKey, value);
                    }
                }
            } else {
                //通过重命名方式解决并发场景下配置读不到值的问题
                //写入新的配置
                for (Map.Entry<String, String> subEntry : newParams.entrySet()) {
                    String paramKey = subEntry.getKey();
                    String value = subEntry.getValue();
                    redisClient.hPut(currentTime, paramKey, value);
                    LOGGER.info("新参数设置成功,redisKey:{},key:{},value:{}", currentTime, paramKey, value);
                }
                redisClient.rename(currentTime, redisKey);
                LOGGER.info("新参数重命名成功,original:{},new:{}", currentTime, redisKey);
            }
            sb.append(redisKey + ",");
        }
        sb.deleteCharAt(sb.length() - 1);
        redisClient.set(RedisKey.DB_CACHE_APP_LIST, sb.toString());
        LOGGER.info("设置applicationName列表成功,{}", sb.toString());
        return oldParamsMap;
    }

    public String getProperty(String key, String defaultValue) {
        String value = redisClient.hGet(this.namespace, key);
        return value == null ? defaultValue : value;
    }

    public Integer getIntProperty(String key, Integer defaultValue) {
        try {
            String value = redisClient.hGet(this.namespace, key);
            return value == null ? defaultValue : Integer.valueOf(value);
        } catch (Exception ex) {
            LOGGER.warn("Conversion failed", ex);
            return defaultValue;
        }
    }

    public Boolean getBooleanProperty(String key, Boolean defaultValue) {
        try {
            String value = redisClient.hGet(this.namespace, key);
            return value == null ? defaultValue : Boolean.valueOf(value);
        } catch (Exception ex) {
            LOGGER.warn("Conversion failed", ex);
            return defaultValue;
        }
    }
}
